﻿
using System;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Web.Hosting;
using System.Web.Mvc.Html;
using System.Xml.Linq;
using Mondial2014.Models.Competition;

namespace Mondial2014.Models.Context
{
    public class Mondial2014ContextInitializer : IDisposable
    {
        private static readonly string CompetitionConfigXml = HostingEnvironment.MapPath("~/ConfigFiles/CompetitionConfig.xml");
        private const string FixtureDateFormat = "d.M.yyyy";

        private readonly Mondial2014DbContext m_Context;
        private readonly XDocument m_ConfigXml;

        public Mondial2014ContextInitializer()
        {
            m_Context = new Mondial2014DbContext();
            m_ConfigXml = XDocument.Load(CompetitionConfigXml);
        }

        public void InitializeContext()
        {
            LoadStages();
            LoadGroupFixtures();
        }

        #region LoadStages

        private void LoadStages()
        {
            var stages =
                from stage in m_ConfigXml.Descendants("Stage")
                select new Stage
                {
                    Level = int.Parse(stage.Attribute("level").Value),
                    Name = stage.Attribute("name").Value
                };

            foreach (var stage in stages.Where(stage => !m_Context.Stages.Any(s => s.Level == stage.Level)))
            {
                m_Context.Stages.Add(stage);
            }

            m_Context.SaveChanges();
        }

        #endregion

        #region LoadGroupFixtures

        private void LoadGroupFixtures()
        {
            var stage0 = m_Context.Stages.Single(s => s.Level == 0);

            var fixtures =
                from fixture in m_ConfigXml.Descendants("GroupFixture")
                select fixture;
            
            var fixtureNumber = 1;
            foreach (var fixture in fixtures)
            {
                var fixtureEntity =
                    m_Context.Fixtures.OfType<GroupFixture>().SingleOrDefault(gf => gf.Number == fixtureNumber) ??
                    m_Context.Fixtures.Add(new GroupFixture {Number = fixtureNumber});
                fixtureNumber++;

                fixtureEntity.Date = DateTime.ParseExact(fixture.Attribute("date").Value, FixtureDateFormat, CultureInfo.DefaultThreadCurrentCulture);
                fixtureEntity.Stage = stage0;
                ((GroupFixture) fixtureEntity).Group = AddGetGroup(int.Parse(fixture.Attribute("group").Value));
                fixtureEntity.Team1 = AddTeamToGroup(fixture.Attribute("team1").Value, ((GroupFixture) fixtureEntity).Group);
                fixtureEntity.Team2 = AddTeamToGroup(fixture.Attribute("team2").Value, ((GroupFixture)fixtureEntity).Group);
            }
        }

        private Group AddGetGroup(int number)
        {
            var group =
                m_Context.Groups.SingleOrDefault(g => g.Number == number) ??
                m_Context.Groups.Add(new Group {Number = number, Teams = new Collection<Team>()});
            m_Context.SaveChanges();
            return group;
        }

        private Team AddTeamToGroup(string name, Group group)
        {
            var team = m_Context.Teams.SingleOrDefault(t => t.Name == name);
            if (team == null)
            {
                team = m_Context.Teams.Add(new Team {Name = name});
                group.Teams.Add(team);
            }
            m_Context.SaveChanges();
            return team;
        }

        #endregion

        #region Dispose

        public void Dispose()
        {
            m_Context.SaveChanges();
            m_Context.Dispose();
        }

        #endregion
    }
}